package wx

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"sort"
)

/*func checkSignature(c *gin.Context) {
	signature := c.Query("signature")
	timestamp := c.Query("timestamp")
	nonce := c.Query("nonce")
}*/

/*func checkSignature(signature, timestamp, nonce, token string) bool {
	array := []string{timestamp, nonce, token}
	sort.Strings(array)
	str := strings.Join(array, "")
	hash := sha1.New()
	hash.Write([]byte(str))
	actualSignature := fmt.Sprintf("%x", hash.Sum(nil))
	return signature == actualSignature
}

//go get github.com/golang-jwt/jwt/v4

const (
	token = "sixah" //设置token
)

func makeSignature(timestamp, nonce string) string { //本地计算signature
	si := []string{token, timestamp, nonce}
	sort.Strings(si)            //字典序排序
	str := strings.Join(si, "") //组合字符串
	s := sha1.New()             //返回一个新的使用SHA1校验的hash.Hash接口
	io.WriteString(s, str)      //WriteString函数将字符串数组str中的内容写入到s中
	return fmt.Sprintf("%x", s.Sum(nil))
}

func validateUrl(w http.ResponseWriter, r *http.Request) bool {
	timestamp := strings.Join(r.Form["timestamp"], "")
	nonce := strings.Join(r.Form["nonce"], "")
	signature := strings.Join(r.Form["signature"], "")
	echostr := strings.Join(r.Form["echostr"], "")
	signatureGen := makeSignature(timestamp, nonce)

	if signatureGen != signature {
		return false
	}
	fmt.Fprintf(w, echostr) //原样返回eechostr给微信服务器
	return true
}

func procSignature(w http.ResponseWriter, r *http.Request) {
	r.ParseForm() //Request需要解析
	if !validateUrl(w, r) {
		log.Println("Wechat Service: This http request is not from wechat platform")
		return
	}
	log.Println("validateUrl Ok")
}

func main() {
	log.Println("Wechat Service: Start!")
	http.HandleFunc("/", procSignature)
	err := http.ListenAndServe(":80", nil)
	if err != nil {
		log.Println("Wechat Service: ListenAndServe Error: ", err)
	}
	log.Println("Wechat Service: Stop!")
}
*/

func Get(w http.ResponseWriter, r *http.Request) {
	client, err := NewClient(r, w, token)
	if err != nil {
		fmt.Println(err)
		w.WriteHeader(403)
		return
	}
	if len(client.Query.Echostr) > 0 {
		w.Write([]byte(client.Query.Echostr))
		return
	}
	w.WriteHeader(403)
	return
}

func NewClient(r *http.Request, w http.ResponseWriter, token string) (*WeiXinClient, error) {
	weiXinClient := new(WeiXinClient)
	weiXinClient.Token = token
	weiXinClient.Request = r
	weiXinClient.ResponseWriter = w
	weiXinClient.initWeiXinQuery()
	fmt.Println(weiXinClient.Query.Signature)
	fmt.Println(weiXinClient.signature())
	if weiXinClient.Query.Signature != weiXinClient.signature() {
		return nil, errors.New("Invalid Signature.")
	}
	return weiXinClient, nil
}

type weiXinQuery struct {
	Signature    string `json:"signature"`
	Timestamp    string `json:"timestamp"`
	Nonce        string `json:"nonce"` //微信发过来的随机一次性字符串
	EncryptType  string `json:"encryptType"`
	MsgSignature string `json:"msgSignature"`
	Echostr      string `json:"echostr"`
}

type WeiXinClient struct {
	Token          string
	Query          weiXinQuery
	Message        map[string]interface{}
	Request        *http.Request
	ResponseWriter http.ResponseWriter
	Methods        map[string]func() bool
}

func (this *WeiXinClient) initWeiXinQuery() {
	var query weiXinQuery
	query.Nonce = this.Request.URL.Query().Get("nonce")                //随机字符串，签名用
	query.Echostr = this.Request.URL.Query().Get("echostr")            //
	query.Signature = this.Request.URL.Query().Get("signature")        //微信的签名
	query.Timestamp = this.Request.URL.Query().Get("timestamp")        //微信发回的时间搓
	query.EncryptType = this.Request.URL.Query().Get("encrypt_type")   //加密解密的方式
	query.MsgSignature = this.Request.URL.Query().Get("msg_signature") //加密解密的消息体签名
	this.Query = query
}

// 签名
func (this *WeiXinClient) signature() string {
	array := sort.StringSlice{this.Token, this.Query.Timestamp, this.Query.Nonce}
	sort.Strings(array)
	str := ""
	for _, s := range array {
		str += s
	}
	h := sha1.New()
	h.Write([]byte(str))
	return fmt.Sprintf("%x", h.Sum(nil))
}

////////////////////

type CheckSignatureRequest struct {
	Signature string `form:"signature"`
	Timestamp string `form:"timestamp"`
	Nonce     string `form:"nonce"`
	Echostr   string `form:"echostr"`
}

/**
 * checkSignature
 * @Description: 用于微信公众号校验服务器
 * @receiver server
 * @param ctx
 */
func CheckSignature(ctx *gin.Context) error {
	//从配置文件中读取token
	//config, _ := utils.LoadConfig()

	var param CheckSignatureRequest
	if err := ctx.ShouldBindQuery(&param); err != nil {
		fmt.Println(ctx, err)
	}
	//	对timestamp、nonce、echostr三个参数进行字典序排序
	slice := sort.StringSlice{param.Timestamp, param.Nonce, token}

	sort.Strings(slice)
	//	将字符串数组拼接成字符串
	str := ""
	for _, value := range slice {
		str += value
	}

	h := sha1.New()
	h.Write([]byte(str))
	hashcode := fmt.Sprintf("%x", h.Sum(nil))

	if hashcode != param.Signature {
		//	校验不通过
		return errors.New("invalid Signature")
	}
	_, err := ctx.Writer.Write([]byte(param.Echostr))
	if err != nil {
		return err
	}
	return nil
}
